package com.hllxd.hism.star.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bj58.zp.cdata.framework.rpc.client.basic.RpcInvoker;
import com.bj58.zp.cdata.framework.rpc.client.basic.RpcReqData;
import com.bj58.zp.cdata.framework.rpc.client.basic.RpcResData;
import com.bj58.zp.cdata.framework.rpc.client.config.client.ServiceProperties;
import com.hllxd.hism.star.util.ConsoleContext;
import com.hllxd.hism.star.util.SyslogManager;
import com.hllxd.hism.star.util.ThreadLocalManager;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.xssf.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import static com.hllxd.hism.star.util.Utils.getTraceID;

@Slf4j
@RestController
@RequestMapping("/star/download")
public class ExportController {

    @Autowired
    private ServiceProperties serviceProperties;

    @Autowired
    private RpcInvoker rpcInvoker;

    @RequestMapping(value = "**/*", method = RequestMethod.POST)
    @ResponseBody
    public void excelExport(@RequestBody String dto, HttpServletRequest request, HttpServletResponse response) throws IOException {
        String uri = request.getRequestURI();
        log.info("param:{}, {}", uri, dto);
        ServicePath sp = initServicePath(uri);
        if (sp == null) {
            log.warn("uri is invalid. {}", uri);
            return;
        }
        String traceID = "", userID = "";
        try {
            ConsoleContext context = ThreadLocalManager.getConsoleContext();
            if (context != null) {
                traceID = context.getTraceId();
                userID = context.getUserID();
            } else {
                userID = "999999";
                traceID = getTraceID();
            }
            log.info("request userID: {}, traceID:{}, uri: {}", userID, traceID, uri);
            SyslogManager.product(traceID, userID, sp.service, sp.path);
            RpcReqData reqData = buildRpcReqData(traceID, userID, sp.path, dto);
            RpcResData<String> rpcResData = rpcInvoker.invoke(sp.service, reqData);
            if (rpcResData == null) {
                return;
            }

            JSONObject resJson = JSONObject.parseObject(rpcResData.getData());
            List<String> headList = resJson.getJSONArray("headList").toJavaList(String.class);
            List<String> fieldList = resJson.getJSONArray("fieldList").toJavaList(String.class);
            String filename = resJson.getString("filename");
            ArrayList<Map<String, Object>> maps = new ArrayList<>();
            JSONArray jsonArray = resJson.getJSONArray("dataMaps");
            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject jsonObject = jsonArray.getJSONObject(i);
                Map<String, Object> innerMap = jsonObject.getInnerMap();
                maps.add(innerMap);
            }
            try (XSSFWorkbook workbook = createExcel(headList, fieldList, maps)) {
                response.reset();
                response.setContentType("application/octet-stream");
                response.addHeader("Access-Control-Expose-Headers", "Content-Disposition");
                //设置下载文件名
                response.addHeader("Content-Disposition", "attachment; filename=" + filename);
                ServletOutputStream outputStream = response.getOutputStream();
                workbook.write(outputStream);
            } catch (Exception e) {
                e.printStackTrace();
                log.error("生成excel出错", e);
            }
        } catch (Exception e) {
            log.warn("Exception: {}, {}, {}", uri, dto, e, e);
        }

    }

    private static RpcReqData buildRpcReqData(String traceID, String userID, String path, String params) {
        RpcReqData thiz = new RpcReqData();
        thiz.setTraceID(traceID);
        thiz.setUserID(userID);
        thiz.setPath(path);
        thiz.setData(JSON.parse(params));
        return thiz;
    }

    static class ServicePath {
        public String service;
        public String path;

        public static ServicePath build(String service, String path) {
            ServicePath thiz = new ServicePath();
            thiz.service = service;
            thiz.path = path;
            return thiz;
        }
    }

    // "/hllxd/api/basic/v1/user/userInfo.do"
    private static ServicePath initServicePath(String uri) {
        try {
            String[] items = uri.split("/");
            StringBuilder sb = new StringBuilder();
            for (int i = 4; i < items.length; ++i) {
                sb.append("/").append(items[i]);
            }
            return ServicePath.build(items[3], sb.toString());
        } catch (Exception e) {
            log.warn("Exception: {}.", e.toString());
            return null;
        }
    }


    /**
     * @param headList  Excel文件Head标题集合
     * @param fieldList Excel文件Field标题集合
     * @param dataList  Excel文件数据内容部分
     */
    public static XSSFWorkbook createExcel(List<String> headList,
                                           List<String> fieldList, List<Map<String, Object>> dataList) {
        // 创建新的Excel 工作簿
        XSSFWorkbook workbook = new XSSFWorkbook();

        // 在Excel工作簿中建一工作表，其名为缺省值
        // 如要新建一名为"效益指标"的工作表，其语句为：
        // HSSFSheet sheet = workbook.createSheet("效益指标");
        XSSFSheet sheet = workbook.createSheet();
        // 在索引0的位置创建行（最顶端的行）
        XSSFRow row = sheet.createRow(0);// 第一个sheet的第一行为标题
        // ===============================================================

        XSSFCellStyle headStyle = workbook.createCellStyle();
        headStyle.setFillForegroundColor(IndexedColors.YELLOW.getIndex());
        headStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        headStyle.setBorderLeft(BorderStyle.THIN);
        headStyle.setBorderBottom(BorderStyle.THIN);
        headStyle.setBorderRight(BorderStyle.THIN);
        headStyle.setBorderTop(BorderStyle.THIN);

        XSSFCellStyle dataStyle = workbook.createCellStyle();
        dataStyle.setBorderLeft(BorderStyle.THIN);
        dataStyle.setBorderBottom(BorderStyle.THIN);
        dataStyle.setBorderRight(BorderStyle.THIN);
        dataStyle.setBorderTop(BorderStyle.THIN);
        for (int i = 0; i < headList.size(); i++) {

            // 在索引0的位置创建单元格（左上端）
            XSSFCell cell = row.createCell(i);
            // 定义单元格为字符串类型
            cell.setCellType(CellType.STRING);
            // 在单元格中输入一些内容
            cell.setCellValue(headList.get(i));
            cell.setCellStyle(headStyle);
        }
        // ===============================================================

        for (int n = 0; n < dataList.size(); n++) {
            // 在索引1的位置创建行（最顶端的行）
            XSSFRow row_value = sheet.createRow(n + 1);
            Map<String, Object> dataMap = dataList.get(n);
            // ===============================================================
            for (int i = 0; i < fieldList.size(); i++) {
                // 在索引0的位置创建单元格（左上端）
                XSSFCell cell = row_value.createCell(i);
                // 定义单元格为字符串类型
                cell.setCellType(CellType.STRING);
                // 在单元格中输入一些内容
                cell.setCellValue(objToString(dataMap.get(fieldList.get(i))));
                cell.setCellStyle(dataStyle);
            }
            // ===============================================================
        }
        return workbook;
    }

    private static String objToString(Object obj) {
        if (obj == null) {
            return "";
        } else {
            if (obj instanceof String) {
                return (String) obj;
            } else if (obj instanceof Date) {
                return null;// DateUtil.dateToString((Date)
                // obj,DateUtil.DATESTYLE_SHORT_EX);
            } else {
                return obj.toString();
            }
        }
    }


}
